package com.crazy.util;

import com.crazy.entity.ImagePosition;
import com.crazy.enums.PositionEnum;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * @author panyonghui
 * @describe PDF工具类
 * @date 2022/5/24 11:15
 */
public class PdfUtils {
    private static Log log = LogFactory.getLog(PdfUtils.class);

    /**
     * @describe pdf文件加密
     * @param pdfPath 原文件路径
     * @param savePath 加密后文件路径
     * @param secretValue 密码
     * @return void
     * @modify
     */
    public static void pdfEncrypt(String pdfPath, String savePath, String secretValue) throws DocumentException, IOException {
        // 读取原文件
        PdfReader pdfReader = new PdfReader(pdfPath);
        try(OutputStream outputStream = new FileOutputStream(savePath);) {
            PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream);
            pdfStamper.setEncryption(secretValue.getBytes(), secretValue.getBytes(), PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128);
            pdfStamper.close();
        } catch (IOException e){
            log.error("pdf加密失败", e);
            throw e;
        } finally {
            if (pdfReader != null) {
                pdfReader.close();
            }
        }
    }

    /**
     * @describe pdf加密
     * @param buf
     * @param secretValue
     * @return byte[]
     * @modify
     */
    public static byte[] pdfEncrypt(byte[] buf, String secretValue) throws DocumentException, IOException {
        // 读取原文件
        PdfReader pdfReader = new PdfReader(buf);
        try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream);
            pdfStamper.setEncryption(secretValue.getBytes(), secretValue.getBytes(), PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128);
            pdfStamper.close();
            return outputStream.toByteArray();
        } catch (IOException e){
            log.error("pdf加密失败", e);
            throw e;
        } finally {
            if (pdfReader != null) {
                pdfReader.close();
            }
        }
    }

    /**
     * @describe 获取pdf页数
     * @param buf
     * @return int
     * @modify
     */
    public static int getPageNum(byte[] buf) throws IOException {
        PdfReader pdfReader = new PdfReader(buf);
        int num = pdfReader.getNumberOfPages();
        pdfReader.close();
        return num;
    }

    /**
     * @describe pdf添加页码
     * @param buf
     * @return byte[]
     * @modify
     */
    public static byte[] addPageNum(byte[] buf) throws IOException, DocumentException {
        byte[] pageStream = buf;
        float fontSize = 12f;
        // 根据一个pdfreader创建一个pdfStamper.用来生成新的pdf.
        PdfReader pdfReader = new PdfReader(buf);
        Rectangle rectangle = pdfReader.getPageSize(1);
        float width = rectangle.getWidth();
        try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream();){
            PdfStamper stamper = new PdfStamper(pdfReader, outputStream);
            // 这个字体是itext-asian.jar中自带的 所以不用考虑操作系统环境问题.
            BaseFont baseFont = BaseFont.createFont("fonts/simsun.ttc,1", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            // baseFont不支持字体样式设定.但是font字体要求操作系统支持此字体会带来移植问题.
            Font font = new Font(baseFont, 10);
            font.setStyle(Font.BOLD);
            font.getBaseFont();
            // 获取页码
            int num = pdfReader.getNumberOfPages();
            for (int i = 1; i <= num; i++) {
                PdfContentByte over = stamper.getOverContent(i);
                over.beginText();
                over.setFontAndSize(font.getBaseFont(), fontSize);
                over.setColorFill(BaseColor.BLACK);
                // 设置页码在页面中的坐标
                over.setTextMatrix(width/2-50, 5);
                over.showText("第" + i + "页 共" + num + "页");
                over.endText();
                over.stroke();
            }
            stamper.close();
            pageStream = outputStream.toByteArray();
        } catch(Exception e) {
            log.error("页码添加失败", e);
            throw e;
        } finally {
            if (pdfReader != null){
                pdfReader.close();
            }
        }
        return pageStream;
    }

    /**
     * @describe pdf添加logo图片
     * @param buf
     * @param imagePath
     * @param imagePosition
     * @return byte[]
     * @modify
     */
    public static byte[] addImageLogo(byte[] buf, String imagePath, ImagePosition imagePosition) throws IOException, DocumentException {
        // 文件不存在返回原数据
        if (!new File(imagePath).isFile()){
            log.info("文件不存在,路径:" + imagePath);
            return buf;
        }
        // 图片宽度
        int width = imagePosition.getWidth();
        // 图片高度
        int height = imagePosition.getHeight();
        try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream();) {
            PdfReader pdfReader = new PdfReader(buf);
            PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream);
            Rectangle rectangle = pdfReader.getPageSize(1);
            float absoluteX = rectangle.getWidth();
            float absoluteY = rectangle.getHeight();
            // 图片坐标处理
            imagePositionProcess(imagePosition, absoluteX, absoluteY);
            int x = imagePosition.getX();
            int y = imagePosition.getY();
            int pageCount = pdfReader.getNumberOfPages();

            //签名图片
            Image contractSealImg = Image.getInstance(imagePath);
            //设置图片位置（左下角的下标是0,0）
            contractSealImg.setAbsolutePosition(x, y);
            //设置图片大小
            contractSealImg.scaleAbsolute(width, height);
            for (int i=1; i <= pageCount; i++) {
                //将签名图片放在pdf文件的第n页
                PdfContentByte over = pdfStamper.getOverContent(i);
                over.saveState();
                PdfGState pdfGState = new PdfGState();
                //给图片设置透明度
                pdfGState.setFillOpacity(1F);
                over.setGState(pdfGState);
                // 将图片添加到pdf文件
                over.addImage(contractSealImg);
                over.restoreState();
                pdfStamper.setFormFlattening(true);
            }
            pdfStamper.close();
            pdfReader.close();
            return outputStream.toByteArray();
        } catch (IOException | DocumentException e){
            log.error("图片添加失败", e);
            throw e;
        }
    }

    /**
     * @describe 图片坐标处理
     * @param imagePosition
     * @param absoluteX
     * @param absoluteY
     * @return void
     * @modify
     */
    private static void imagePositionProcess(ImagePosition imagePosition, float absoluteX, float absoluteY){
        // 图片宽度
        int width = imagePosition.getWidth();
        // 图片高度
        int height = imagePosition.getHeight();
        // x轴坐标
        int x = imagePosition.getX();
        // y轴坐标
        int y = imagePosition.getY();
        // x轴边距
        int marginX = imagePosition.getMarginX();
        // y轴边距
        int marginY = imagePosition.getMarginY();
        PositionEnum positionEnum = imagePosition.getPositionEnum();
        // 设置了角落就按角落坐标处理，没设置角落就按指定的坐标处理
        if (positionEnum != null){
            switch (positionEnum){
                case UPPER_LEFT:
                    // 左上角
                    x = marginX;
                    y = (int) (absoluteY - height - marginY);
                    break;
                case UPPER_RIGHT:
                    // 右上角
                    x = (int) (absoluteX - width - marginX);
                    y = (int) (absoluteY - height - marginY);
                    break;
                case LOWER_LEFT:
                    // 左下角
                    x = marginX;
                    y = marginY;
                    break;
                case LOWER_RIGHT:
                    // 右下角
                    x = (int) (absoluteX - width - marginX);
                    y = marginY;
                    break;
                case TOP:
                    // 上中
                    x = (int) ((absoluteX - width)/2);
                    y = (int) (absoluteY - height - marginY);
                    break;
                case BOTTOM:
                    // 下中
                    x = (int) ((absoluteX - width)/2);
                    y = marginY;
                    break;
                case LEFT:
                    // 左中
                    x = marginX;
                    y = (int) (absoluteY - height)/2;
                    break;
                case RIGHT:
                    // 右中
                    x = (int) (absoluteX - width - marginX);
                    y = (int) (absoluteY - height)/2;
                    break;
            }
        }
        imagePosition.setX(x);
        imagePosition.setY(y);
    }

    public static void main(String[] args) throws IOException, DocumentException {
        String pdfPath = "/home/test/22dddc962d4ea10b9aaf6c67832c05e7.pdf";
        String savePath = "/home/test/22dddc962d4ea10b9aaf6c67832c05e7_res.pdf";
        String logoPath = "C:\\Users\\crazycat\\Desktop\\微信截图_20220627114957.png";
        String secretValue = "test123";
//        PdfUtil.pdfEncrypt(pdfPath, savePath, secretValue);
        byte[] buf = FileUtils.fileToBytes(pdfPath);
        buf = PdfUtils.addPageNum(buf);
        ImagePosition imagePosition = new ImagePosition();
        imagePosition.setWidth(171);
        imagePosition.setHeight(67);
        imagePosition.setMarginX(50);
        imagePosition.setMarginY(100);
        imagePosition.setPositionEnum(PositionEnum.UPPER_LEFT);
        buf = addImageLogo(buf, logoPath, imagePosition);
        FileUtils.bytesToFile(savePath, buf);
    }
}
